#pragma once
#include <string>
#include <iostream>
#include <typeinfo>
#include <memory>
#include <unordered_map>
#include <functional>
#ifdef __GNUC__
#include <cxxabi.h>
#endif

namespace CQ
{
	const std::string CQReflectName = "CQReflect";

	struct CQReflectStruct
	{
		std::string moduleName;
		std::string className;
		std::string paraStr;
	};

	struct CQVirtual
	{
		virtual void Say() = 0;
	};

	template<typename ...Targs>
	class CQReflectFactory
	{
	public:
		//typedef Actor* (*ActorCreateFunction)();
		//std::function< Actor*(Targs...args) > pp;

		static CQReflectFactory* Instance() {
			if (!m_pActorFactory) { m_pActorFactory = new CQReflectFactory(); }
			return m_pActorFactory;
		}

		virtual ~CQReflectFactory() {}

		//Lambda: static std::string ReadTypeName(const char * name)

		//bool Regist(const std::string& strTypeName, ActorCreateFunction pFunc)
		//bool Regist(const std::string& strTypeName, std::function<Actor*()> pFunc)
		bool Regist(const std::string& strTypeName, std::function<CQVirtual* (Targs&&... args)> pFunc) {
			if (!pFunc) { return false; }
			return m_mapCreateFunction.insert(std::make_pair(strTypeName, pFunc)).second;
		}

		CQVirtual* Create(const std::string& strTypeName, Targs&&... args) {
			auto iter = m_mapCreateFunction.find(strTypeName);
			if (iter == m_mapCreateFunction.end()) { return nullptr; }
			else { return iter->second(std::forward<Targs>(args)...); }
		}

	private:
		CQReflectFactory() { }
		static CQReflectFactory<Targs...>* m_pActorFactory;
		std::unordered_map<std::string, std::function<CQVirtual* (Targs&&...)> > m_mapCreateFunction;
	};

	template<typename ...Targs>
	CQReflectFactory<Targs...>* CQReflectFactory<Targs...>::m_pActorFactory = nullptr;

	template<typename T, typename ...Targs>
	class CQReflect
	{
	public:
		struct CQRegister
		{
			CQRegister() {
				char* szDemangleName = nullptr;
				std::string strTypeName;
#ifdef _MSC_VER
				szDemangleName = const_cast<char*>(typeid(T).name());
				if (szDemangleName) strTypeName = szDemangleName + 6; // 6 is strlen("class ")
#elif defined(__GNUC__)
				szDemangleName = abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, nullptr);
				if (szDemangleName) {
					strTypeName = szDemangleName;
					free(szDemangleName);
				}
#else
#error unexpected c complier (msc/gcc), Need to implement this method for demangle
#endif
				CQReflectFactory<Targs...>::Instance()->Regist(strTypeName, CreateObject);
			}
			inline void do_nothing()const { }
		};
		CQReflect() { m_oRegister.do_nothing(); }
		virtual ~CQReflect() { m_oRegister.do_nothing(); }

		static T* CreateObject(Targs&&... args) { return new T(std::forward<Targs>(args)...); }
		//virtual void Say() { std::cout << "DynamicCreator say" << std::endl; }
		static CQRegister m_oRegister;
	};

	template<typename T, typename ...Targs>
	typename CQReflect<T, Targs...>::CQRegister CQReflect<T, Targs...>::m_oRegister;

	class ObjMaker
	{
	public:
		template<typename ...Targs>
		static CQVirtual* CreateActor(const std::string& strTypeName, Targs&&... args) {
			return CQReflectFactory<Targs...>::Instance()->Create(strTypeName, std::forward<Targs>(args)...);
		}
	};

	/***  Example:
	class Test : public CQVirtual, CQReflect<Test>, CQReflect<Test, std::string, int>
	{
	public:
		Test() { std::cout << "Create Test! " << std::endl; }
		Test(const std::string& strType, int iSeq) { std::cout << "Create Test: " << strType << " " << iSeq << std::endl; }
		virtual void Say() { std::cout << "I am Test" << std::endl; }
	};
	***/
}

#ifdef _CQReflectAPI
	#define  CQReflect_API  __declspec(dllexport)
#else
	#define  CQReflect_API
#endif

#define __CQCreaterFuncDefine__(__CQ_NAME__)\
inline std::string CQ##__CQ_NAME__() {return std::string(__FUNCTION__);}\
extern "C" CQReflect_API inline CQ::CQVirtual*  CQ##__CQ_NAME__(const std::string& name, const std::string& para){\
if (para != "") return CQ::ObjMaker::CreateActor(name, para); else return CQ::ObjMaker::CreateActor(name);};\
static std::string CQCreaterStr = CQ##__CQ_NAME__();
__CQCreaterFuncDefine__(CreaterFunction) // Just need to rename string : CreaterFunction